/*
 * Copyright (c) 2011 Obix Labs Limited
 * Redistribution and use in source and binary forms, 
 * with or without modification, are permitted provided 
 * that the following conditions are met:
 * 
 * 		Redistribution of source code must retain the above 
 * 		copyright notice, this list of conditions and the 
 * 		following disclaimer.
 *
 * 		Redistribution in binary form must reproduce the 
 * 		above copyright notice, this list of conditions 
 * 		and the following disclaimer in the documentation 
 * 		and/or other materials provided with the distribution.
 * 
 * 	THIS SOFTWARE IS PROVIDED "AS IS," WITHOUT A WARRANTY OF 
 * 	ANY KIND. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS 
 * 	AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, 
 * 	FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, 
 * 	ARE HEREBY EXCLUDED. OBIX LABS LIMITED ("Obix Labs") AND ITS 
 * 	LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE 
 * 	AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR 
 * 	ITS DERIVATIVES. IN NO EVENT WILL Obix Labs OR ITS LICENSORS BE 
 * 	LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, 
 * 	INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE 
 * 	DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF 
 * 	LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS 
 * 	SOFTWARE, EVEN IF Obix Labs HAS BEEN ADVISED OF THE POSSIBILITY OF 
 * 	SUCH DAMAGES.
 */

package com.obixlabs.commons.naming;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.Name;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;

/**
 * <p>
 * Utility class which provides functionality for performing Java naming operations.
 * </p>
 */
public final class NamingUtils 
{
    /**
     * <p>
     * Private default constructor to prevent accidental initialisation.
     * </p>
     */
    private NamingUtils() {}
    
    /**
     * <p>
     * Binds an object into the default context under the specified address. This method is similar in all other respects
     * to {@link #bind(String, String, Object)} except that it does not allow the caller to specify the context name and
     * as such will always bind into the default context as identified by <i>""</i> i.e. the empty string.
     * </p>
     * <p>
     * In essence, call this method is equivalent to calling {@link #bind(String, String, Object)} with the context name 
     * specified as an empty string.
     * </p>
     * 
     * @param jndiLocation  The location under which to bind the object.
     * @param object The object to be bound into the default naming context.
     * @throws NamingException      If unable to obtain the default context, or if unable to create 
     * any of the intermediate sub-contexts leading to the bind location. More 
     * generally if a problem occurs while interacting with the underlying naming API.
     */
	public static void bind(	String jndiLocation, Object object) throws NamingException
	{ bind("", jndiLocation, object); }

	
	/**
	 * <p>
	 * Binds a value into the named context, under the specified
	 * location. This method will create all non-existent sub-contexts leading to the specified 
	 * location.
	 * </p>
	 * 
	 * <p>
	 * Note that this method is similar to {@link #bind(String, Object)}, except that it allows the 
	 * caller to specify the context name. This is probably more usefull in environments with 
	 * federated naming.
	 * </p>
	 * 
	 * @param contextName The name of the context into which the object is to be bound. 
	 * @param jndiLocation The location (name) to which the specified object 
	 * should be bound.
	 * @param object The object to be bound into the specified JNDI location .
	 * @throws NamingException If unable to obtain the identified context, or if unable to create 
	 * any of the intermediate sub-contexts leading to the bind location. More 
	 * generally if a problem occurs while interacting with the underlying naming API.
	 */
	public static void bind(	String contextName, 
								String jndiLocation, Object object) 
								throws NamingException 
	{
	    //get the initial context
		InitialContext initialContext = null;
		
		try
		{			
			initialContext=new InitialContext();
	
			//parse the name we were given
			//also, check that contextName is not null as this 
			//may interfere with some providers
			if (contextName==null) contextName = new String();
			Name jndiName = initialContext.getNameParser(contextName).parse(jndiLocation);
			
			//if the name has any subcontexts then the following loop will execute
			Context subContext;					
			String subContextName;
			
			Context parentContext=initialContext;
			Name currentJndiName=jndiName;
			
			while (currentJndiName.size()>1) //while there is any subcontext
			{
				subContextName=currentJndiName.get(0);			
				try{
				    subContext= (Context)parentContext.lookup(subContextName);
				}catch (NameNotFoundException nnf_exce){
				    subContext=parentContext.createSubcontext(subContextName);
				}
				   
				//re-initialise for the next round of the loop
				currentJndiName=currentJndiName.getSuffix(1); 			    
				parentContext=subContext;
			}
						
			parentContext.rebind(currentJndiName,object);
			
		}
		finally { close(initialContext);} 
		
	}//end method def
	
	
	/**
	 * <p>
	 * Closes the given context, thus releasing its resources.
	 * </p>
	 * 
	 * @param context	The context to close.
	 */
	public static void close(Context context)
	{
		try
		{
			if (context!=null);
				context.close();
		} catch (Throwable t){}
	}

}//end class def